#include "test_helpers.h"
#include <spdlog/spdlog.h>
#include <random>
#include <thread>
#include <chrono>

namespace MessageFramework {
namespace Test {

RedisPool* TestHelpers::getTestRedisPool() {
    static RedisPool& poolRef = RedisPool::getInstance();

    if (!poolRef.isInitialized()) {
        TraderEngine::RedisConfig config;
        config.host = "127.0.0.1";
        config.port = 6379;
        config.password = "redis_EX7Nms";
        config.pool_size = 10;

        poolRef.initialize(config);

        spdlog::info("Test Redis pool initialized");
    }

    return &poolRef;
}

void TestHelpers::cleanupRedis(const std::string& streamPattern) {
    RedisPool* pool = getTestRedisPool();
    auto conn = pool->getConnection();

    if (!conn) {
        spdlog::error("Failed to get Redis connection for cleanup");
        return;
    }

    try {
        // 查找匹配的Stream
        auto keys = conn->keys(streamPattern);

        // 删除所有匹配的Stream
        for (const auto& key : keys) {
            conn->del(key);
        }

        spdlog::debug("Cleaned up {} test streams", keys.size());

    } catch (const std::exception& e) {
        spdlog::error("Failed to cleanup Redis: {}", e.what());
    }

    pool->returnConnection(conn);
}

MessageHeader TestHelpers::createTestHeader(const std::string& messageType,
                                            const std::string& publisherId) {
    MessageHeader header;

    std::string msgId = MessageHeader::generateMessageId();
    std::strncpy(header.messageId, msgId.c_str(), sizeof(header.messageId) - 1);

    std::strncpy(header.messageType, messageType.c_str(), sizeof(header.messageType) - 1);
    std::strncpy(header.publisherId, publisherId.c_str(), sizeof(header.publisherId) - 1);
    std::strncpy(header.targetStream, "test_stream", sizeof(header.targetStream) - 1);

    std::strcpy(header.version, "1.0");
    header.timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
        std::chrono::high_resolution_clock::now().time_since_epoch()).count();
    header.priority = 5;
    std::strcpy(header.contentType, "JSON");

    return header;
}

std::string TestHelpers::createTestBody(const std::string& content) {
    return "{\"content\":\"" + content + "\"}";
}

bool TestHelpers::headersEqual(const MessageHeader& h1, const MessageHeader& h2) {
    return std::strcmp(h1.messageId, h2.messageId) == 0 &&
           std::strcmp(h1.messageType, h2.messageType) == 0 &&
           std::strcmp(h1.publisherId, h2.publisherId) == 0 &&
           std::strcmp(h1.targetStream, h2.targetStream) == 0;
}

std::string TestHelpers::randomString(size_t length) {
    static const char charset[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::uniform_int_distribution<> dis(0, sizeof(charset) - 2);

    std::string result;
    result.reserve(length);

    for (size_t i = 0; i < length; ++i) {
        result += charset[dis(gen)];
    }

    return result;
}

bool TestHelpers::waitFor(std::function<bool()> condition,
                         int timeoutMs,
                         int intervalMs) {
    auto start = std::chrono::steady_clock::now();
    auto timeout = std::chrono::milliseconds(timeoutMs);

    while (std::chrono::steady_clock::now() - start < timeout) {
        if (condition()) {
            return true;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs));
    }

    return false;
}

// ==================== RedisTestBase ====================

void RedisTestBase::SetUp() {
    redisPool = TestHelpers::getTestRedisPool();
    testStreamPrefix = "test_" + TestHelpers::randomString(8);

    spdlog::set_level(spdlog::level::debug);
    spdlog::info("Test started with prefix: {}", testStreamPrefix);
}

void RedisTestBase::TearDown() {
    // 清理测试数据
    TestHelpers::cleanupRedis(testStreamPrefix + "*");
    spdlog::info("Test cleanup completed");
}

// ==================== MockHandler ====================

MockHandler::MockHandler(const std::string& messageType)
    : m_messageType(messageType) {
}

int MockHandler::handleMessage(const Message& message) {
    m_callCount++;
    m_lastMessage = message;

    spdlog::debug("MockHandler called {} times, messageId: {}",
                 m_callCount, message.header.messageId);

    return 0;
}

} // namespace Test
} // namespace MessageFramework
